using System;
using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;

namespace SharpGL.SceneGraph.Cameras
{
	/// <summary>
	/// This camera contains the data needed to perform a Perspective transformation
	/// to the projection matrix.
	/// </summary>
	[DataContract()]
	public class PerspectiveCamera : Camera
    {
        #region Private Fields

        /// <summary>
        /// The field of view. 
        /// </summary>
        [DataMember()]
        private double fieldOfView = 60.0f;

        /// <summary>
        /// The near clip.
        /// </summary>
        [DataMember()]
        private double near = 0.5f;

        /// <summary>
        /// The far flip.
        /// </summary>
        [DataMember()]
        private double far = 40.0f;

        #endregion Private Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PerspectiveCamera"/> class.
        /// </summary>
		public PerspectiveCamera()
		{
			Name = "Camera (Perspective)";
		}

        #endregion Constructors

        #region Public Methods

        /// <summary>
		/// This is the class' main function, to override this function and perform a 
		/// perspective transformation.
		/// </summary>
        public override void TransformProjectionMatrix(OpenGL gl)
		{
            if (OpenGL.IsValidContext(gl))
            {
                //  Perform the perspective transformation.
                //currentOpenGLContext.Translate(Position.X, Position.Y, Position.Z);
                gl.Perspective(fieldOfView, AspectRatio, near, far);
                Point3D target = new Point3D(0, 0, 0);
                Vector3D upVector = new Vector3D(0, 0, 1);
                //  Perform the look at transformation.
                gl.LookAt((double)Position.X, (double)Position.Y, (double)Position.Z,
                    (double)target.X, (double)target.Y, (double)target.Z,
                    (double)upVector.X, (double)upVector.Y, (double)upVector.Z);
            }
		}

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the field of view.
        /// </summary>
        /// <value>
        /// The field of view.
        /// </value>
        [Description("The angle of the lense of the camera (60 degrees = human eye)."), Category("Camera (Perspective")]
        public double FieldOfView
        {
            get { return fieldOfView; }
            set
            {
                if (fieldOfView != value)
                {
                    fieldOfView = value;

                    NotifyPropertyChanged("FieldOfView");
                }
            }
        }
		
        /// <summary>
        /// Gets or sets the near.
        /// </summary>
        /// <value>
        /// The near.
        /// </value>
        [Description("The near clipping distance."), Category("Camera (Perspective")]
        public double Near
        {
            get { return near; }
            set
            {
                if (near != value)
                {
                    near = value;

                    NotifyPropertyChanged("Near");
                }
            }
        }

        /// <summary>
        /// Gets or sets the far.
        /// </summary>
        /// <value>
        /// The far.
        /// </value>
        [Description("The far clipping distance."), Category("Camera (Perspective")]
        public double Far
        {
            get { return far; }
            set
            {
                if (far != value)
                {
                    far = value;

                    NotifyPropertyChanged("Far");
                }
            }
        }

        #endregion Public Properties
    }
}
